package com.xiaoger.async.config;

import com.xiaoger.async.async.AsyncExceptionHandler;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 * @author xjx
 * @date 2022/5/11 15:57
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig implements AsyncConfigurer {

    /**
     * 核心线程数（默认线程数）线程池创建时候初始化的线程数
     */
    private static final int CORE_POOL_SIZE = 10;
    /**
     * 最大线程数 线程池最大的线程数，只有在缓冲队列满了之后才会申请超过核心线程数的线程
     */
    private static final int MAX_POOL_SIZE = 100;
    /**
     * 允许线程空闲时间（单位：默认为秒）当超过了核心线程之外的线程在空闲时间到达之后会被销毁
     */
    private static final int KEEP_ALIVE_TIME = 10;
    /**
     * 缓冲队列数 用来缓冲执行任务的队列
     */
    private static final int QUEUE_CAPACITY = 200;
    /**
     * 线程池名前缀 方便我们定位处理任务所在的线程池
     */
    private static final String THREAD_NAME_PREFIX = "Async-Service-";

    /**
     * 初始化线程池
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        taskExecutor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
        taskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);

        /**
         * ThreadPoolExecutor.AbortPolicy             丢弃任务并抛出RejectedExecutionException异常(默认)。
         * ThreadPoolExecutor.DiscardPolic            丢弃任务，但是不抛出异常。
         * ThreadPoolExecutor.DiscardOldestPolicy     丢弃队列最前面的任务，然后重新尝试执行任务
         * ThreadPoolExecutor.CallerRunsPolic         由调用线程处理该任务
         */
        // 线程池对拒绝任务的处理策略 采用了CallerRunsPolicy策略，当线程池没有处理能力的时候，该策略会直接在 execute 方法的调用线程中运行被拒绝的任务；如果执行程序已关闭，则会丢弃该任务
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        //如果不初始化，导致找到不到执行器
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        //自定义异步方法异常拦截器
        return new AsyncExceptionHandler();
    }

}
